#ifndef VEC4_H
#define VEC4_H

#include<iostream>
#include<windows.h>

template<class T>
class Vec4
{
public:
	T x, y, z, w;


	
	Vec4<T>(T _x, T _y, T _z) {
		x = _x; y = _y; z = _z;
	}
	Vec4<T>(T _x, T _y, T _z, T _w) {
		x = _x; y = _y; z = _z;
		w = _w;
	}

	Vec4<T>() {
		x = 0; y = 0; z = 0;
		w = 1;
	}

	void standard() {
		if (w = 0) return;
		x /= w;
		y /= w;
		z /= w;
		w = 1;
	}

	T lengthSquared() {
		return x * x + y * y + z * z;
	}

	T length() {
		return std::sqrt(lengthSquared());
	}

	Vec4<T>& Normalize() {
		*this = *this / length();
		return *this;
	}

	T Dot(const Vec4<T>& vec) {
		return x * vec.x + y * vec.y + z * vec.z;
	}


	

	Vec4<T> operator+(const Vec4<T>& vec) {
		return Vec4<T>(x + vec.x, y + vec.y, z + vec.z);
	}

	

	Vec4<T> operator-(const Vec4<T>& vec) {
		return Vec4<T>(x - vec.x, y - vec.y, z - vec.z);
	}


	Vec4<T> operator*(const Vec4<T>& vec) {
		return Vec4<T>(x * vec.x, y * vec.y, z * vec.z);
	}

	Vec4<T> operator/(const Vec4<T>& vec) {
		return Vec4<T>(x / vec.x, y / vec.y, z / vec.z);
	}




	Vec4<T> operator-() {
		return Vec4<T>(-x,-y,-z);
	}


	Vec4<T>& operator+=(const Vec4<T>& v) {
		x += v.x;
		y += v.y;
		z += v.z;
		return *this;
	}

	Vec4<T>& operator-=(const Vec4<T>& v) {
		x -= v.x;
		y -= v.y;
		z -= v.z;
		return *this;
	}

	Vec4<T>& operator*=(T t) {
		x *= t;
		y *= t;
		z *= t;
		return *this;
	}

	Vec4<T>& operator/=(T t) {
		return *this *= 1 / t;
	}

	void print() {
		std::cout << "(x,y,z)=(" << x << ", " << y << ", " << z<<std::endl;
	}

};


using Vec4f = Vec4<float>;
using Vec4i = Vec4<int>;
using Vec4d = Vec4<double>;


//template<class T>
//inline std::ostream& operator<<(std::ostream& out, const Vec4<T>& v) {
//	return out << v.x << ' ' << v.y << ' ' << v.z;
//}

template<typename T>
inline Vec4<T> operator+(const Vec4<T>& u, const Vec4<T>& v) {
	return Vec4<T>(u.x + v.x, u.y + v.y, u.z + u.z);
}

template<typename T>
inline Vec4<T> operator-(const Vec4<T>& u, const Vec4<T>& v) {
	return Vec4<T>(u.x - v.x, u.y - v.y, u.z - u.z);
}

template<typename T>
inline Vec4<T> operator*(const Vec4<T>& u, const Vec4<T>& v) {
	return Vec4<T>(u.x * v.x, u.y * v.y, u.z * u.z);
}

template<typename T>
inline Vec4<T> operator*(const Vec4<T>& u, const T t) {
	return Vec4<T>(u.x * t, u.y * t, u.z * t);
}

template<typename T>
inline Vec4<T> operator*(const T t, const Vec4<T>& v) {
	return v * t;
}

template<typename T>
inline Vec4<T> operator/(const Vec4<T>& v, const T t) {
	return (1 / t) * v;
}


template<typename T>
inline T Dot(const Vec4<T>& u, const Vec4<T>& v) {
	return u.x*v.x+u.y*v.y+u.z*v.z;
}


template<typename T>
inline Vec4<T> Cross(const Vec4<T>& u, const Vec4<T>& v) {
	return Vec4<T>(u.y*v.z-u.z*v.y,u.z*v.x-u.x*v.z,u.x*v.y-u.y*v.x);
}

template<typename T>
inline Vec4<T> Lerp(const Vec4<T>& u, const Vec4<T>& v, T t) {
	return u + (v - u) * t;
}

void Vec4<T>::print() {
	std::cout << "(x,y,z)=(" << x << ", " << y << ", " << z << std::endl;
}


class Vec2 {
public:
	int x, y;
	Vec2():x(0),y(0) {}
	Vec2(float _x,float _y): x(_x),y(_y) {}

	Vec2 operator+(const Vec2& v)const {
		return Vec2(x + v.x, y + v.y);
	}
	Vec2 operator-(const Vec2& v)const  {
		return Vec2(x - v.x, y - v.y);
	}
	Vec2 operator*(float t)const  {
		return Vec2(x*t, y*t);
	}
	Vec2 operator+(float t)const {
		return Vec2(x*t, y*t);
	}
};









#endif // !VEC4_H


